home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Mac Game Programming Gurus
/
TricksOfTheMacGameProgrammingGurus.iso
/
More Source
/
Libraries
/
VideoToolbox 95.04.18
/
Demos
/
Grating.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-12
|
8KB
|
212 lines
/*
Grating.c
This demo shows how to load the clut and put a vignetted grating onto the
screen. It also saves the image to disk as a PICT file. This demo has been kept
as simple as possible, to enhance readability, forsaking accurate control of
time and contrast of the stimulus. The FlickeringGrating demo, on the other
hand, is somewhat more elaborate and presents a research-grade stimulus if the
LuminanceRecord.h calibration data are accurate.
For a real experiment there are some refinements you should consider. This demo
takes a while to create the image on the screen, but you probably want
frame-accurate timing in your experiment. You could either create the image in
an offscreen GWorld and copy it to the screen with CopyBitsQuickly. Or you could
set the clut to uniform gray (every clut entry equal to the background
luminance) while you're computing the image on-screen, and then load a grayscale
ramp into the clut when you want the display to start. Similarly you can make
the image disappear by loading a new image, calling EraseRect(), or loading
a uniform-gray clut.
Another issue that matters for a real experiment is gamma correction. The
numbers loaded into the clut are faithfully transformed into voltages by the
three digital-to-analog converters on your video card, but the resulting
luminance produced on your monitor will be an approximately parabolic function
of the video voltage. Apple provides crude gamma correction by means of a
generic 8-bit gamma table in the video driver, which does make things look
better, but is not accurately matched to the gamma of your particular monitor,
which depends on the current settings of its brightness and contrast knobs.
Furthermore the Apple 8-bit gamma-correction scheme, which simply transforms the
nominal 8-bit clut value into a new 8-bit clut value, necessarily restricts the
range of available values, mapping several onto one output value, and omitting
some output values. In other words your luminances will be 8-bit quantized
twice, both before and after gamma correction. It is preferable to do gamma
correction first, without quantization. Therefore I suggest you eliminate
Apple's gamma correction, by calling GDUncorrectedGamma(), and use the
Luminance.c package to do gamma correction. That package implements the
published algorithm of Pelli and Zhang (1991). The FlickeringGrating demo uses
Luminance.c.
Why not merge main() and Grating()? The call to Require() checks for any needed
hardware. It is vital that a test for the presence of a needed floating point
unit be done before entering any routine, e.g. Grating(), that uses the fpu,
because the THINK C compiler typically produces code that accesses the fpu, to
save fpu registers, at the beginning of the routine, so any subsequent check
would be too late.
HISTORY:
2/7/93 dgp wrote it, as an answer to questions from Bill Merigan and David Brainard.
2/18/93 dgp added fpu test.
2/23/93 dgp use new GDOpenWindow1 and GDDisposeWindow1.
4/18/93 dgp support directType.
7/7/93 dgp prefer screen 1. Added ScrollRect for compatibility with Radius PowerView.
10/2/93 dgp added SAVE_PICT to test PixMapToPICT().
4/27/94 dgp now ask user whether to save grating as PICT.
8/11/94 dgp don't redefine "sin".
9/5/94 dgp removed assumption in printf's that int==short.
3/20/95 dgp removed SelectWindow() workaround for CW5 SIOUX bug.
4/11/95 dgp set and restore display depth and color. Use ChooseScreen().
*/
#include "VideoToolbox.h"
#include <math.h>
#if (THINK_C || THINK_CPLUS)
#include <console.h>
#endif
#if __MWERKS__
#include <SIOUX.h>
#endif
#if UNIVERSAL_HEADERS
#include <LowMem.h>
#else
#define LMGetMBarHeight() (* (short *) 0x0BAA)
#define LMSetMBarHeight(MBarHeightValue) ((* (short *) 0x0BAA) = (MBarHeightValue))
#endif
#include "mc68881.h"
#if mc68881 && THINK_C // use explicit fpu instructions for highest possible speed
#undef exp
#define exp _exp
#endif
void Grating(void);
#define SIZE 300
#define POWERVIEW 0
void main(void)
{
Require(gestalt8BitQD);
Grating();
}
void Grating(void)
{
short i,j,error,clutSize,pixelSize,oldPixelSize,oldIsColor,mode;
short preferredPixelSize[6]={8,32,16,4,2,1}; // Order of preference
GDHandle device;
static ColorSpec table[256];
WindowPtr window,oldPort;
Rect r;
double a,fX[SIZE],fY[SIZE];
char string[100];
Point pt;
Boolean savePict=1,saveEPS=1;
StackGrow(10000);
#if (THINK_C || THINK_CPLUS)
console_options.top = 0;
console_options.left = 0;
console_options.nrows = 4;
console_options.ncols = 60;
printf("\n");
#elif __MWERKS__
SIOUXSettings.toppixel=LMGetMBarHeight()+1; // allow for menu bar only
SIOUXSettings.leftpixel=1;
SIOUXSettings.rows=4;
SIOUXSettings.columns=60;
SIOUXSettings.autocloseonquit=0;
SIOUXSettings.showstatusline=0;
SIOUXSettings.asktosaveonclose=0;
printf("\n");
#else
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
InitCursor();
#endif
printf("Welcome to Grating.\n");
GetPort(&oldPort);
/* Find device corresponding to the experimental screen. */
for(i=8;i>=0;i--){
device = GetScreenDevice(i);
if(device!=NULL) break;
}
do{
if(GetScreenDevice(1)!=NULL)i=ChooseScreen(i,"Which screen?");
else i=0;
device=GetScreenDevice(i);
}while(device==NULL);
// Try to get the best possible pixelSize.
oldPixelSize=(**(**device).gdPMap).pixelSize;
oldIsColor=TestDeviceAttribute(device,gdDevType);
if(oldPixelSize!=preferredPixelSize[0] && NewPaletteManager()){
for(i=0;i<sizeof(preferredPixelSize)/sizeof(*preferredPixelSize);i++){
if(oldPixelSize==preferredPixelSize[i] && oldIsColor)break;
mode=HasDepth(device,preferredPixelSize[i],0,0);
if(mode!=0){
printf("Changing pixelSize to %d bits, color.\n",(int)preferredPixelSize[i]);
error=SetDepth(device,preferredPixelSize[i],1<<gdDevType,1); // color
break;
}
}
}
pixelSize=(**(**device).gdPMap).pixelSize;
savePict=Choose(savePict,"Save grating to disk as a PICT file?\n",noYes,2);
saveEPS=Choose(saveEPS,"Save grating to disk as an EPS file?\n",noYes,2);
// Load the clut with a grayscale ramp.
GDSaveGamma(device);
GDUncorrectedGamma(device); // Tell the driver to faithfully copy our colors into
// the clut without any transformation.
clutSize=GDClutSize(device);
for(i=0;i<clutSize;i++){
table[i].rgb.red=table[i].rgb.green=table[i].rgb.blue=i*(long)0xffff/(clutSize-1);
}
error=GDSetEntriesByType(device,0,clutSize-1,table);
// Open window and put grating in it.
window=GDOpenWindow1(device);
SetPort(window);
PmBackColor((clutSize-1)/2); // This works because GDOpenWindow1 marked
EraseRect(&window->portRect); // all the colors as pmExplicit.
SetRect(&r,0,0,SIZE,SIZE);
CenterRectInRect(&r,&window->portRect);
for(i=0;i<SIZE;i++){
a=(i-SIZE/2)/(SIZE/6.);
fY[i]=exp(-a*a);
fX[i]=fY[i]*sin((i-SIZE/2)*(2.0*PI/80.0));
}
pt.h=pt.v=0;
LocalToGlobal(&pt);
ShieldCursor(&r,pt);
for(j=0;j<SIZE;j++){
unsigned long row[SIZE];
for(i=0;i<SIZE;i++) row[i]=0.5+(clutSize-1)*0.5*(1.0+fY[j]*fX[i]);
if(pixelSize==16)for(i=0;i<SIZE;i++) row[i]*=1+(1<<5)+(1<<10);
if(pixelSize==32)for(i=0;i<SIZE;i++) row[i]*=1+(1<<8)+(1UL<<16);
SetPixelsQuickly(r.left,r.top+j,row,SIZE);
}
ShowCursor();
if(savePict){
PixMapToPICT("grating.pict",((CWindowPtr)window)->portPixMap
,&r,2,NULL);
printf("Image was saved to disk as file “grating.pict”.\n");
}
if(saveEPS){
WindowToEPS((CWindowPtr)window,"grating.eps",&r,&r,0,0,NULL);
printf("Image was saved to disk as file “grating.eps.\n");
}
SetPort((WindowPtr)oldPort);
printf("Done. Hit return to quit.\n");
gets(string);
GDDisposeWindow1(window);
GDRestoreGamma(device);
GDRestoreDeviceClut(device);
// restore
error=SetDepth(device,oldPixelSize,1<<gdDevType,oldIsColor);
#if (THINK_C || THINK_CPLUS)
abort();
#elif __MWERKS__
SIOUXSettings.autocloseonquit=1;
#endif
}